// matrix/kaldi-vector.cc

// Copyright 2009-2011  Microsoft Corporation;  Lukas Burget;
//                      Saarland University;   Go Vivace Inc.;  Ariya Rastrow;
//                      Petr Schwarz;  Yanmin Qian;  Jan Silovsky;
//                      Haihua Xu; Wei Shi
//                2015  Guoguo Chen
//                2017  Daniel Galvez
//                2019  Yiwen Shao

// See ../../COPYING for clarification regarding multiple authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing permissions and
// limitations under the License.

#include "matrix/kaldi-vector.h"

#include <algorithm>
#include <string>

#include "matrix/kaldi-matrix.h"

namespace kaldi {

template <typename Real>
inline void Vector<Real>::Init(const MatrixIndexT dim) {
    KALDI_ASSERT(dim >= 0);
    if (dim == 0) {
        this->dim_ = 0;
        this->data_ = NULL;
        return;
    }
    MatrixIndexT size;
    void *data;
    void *free_data;

    size = dim * sizeof(Real);

    if ((data = KALDI_MEMALIGN(16, size, &free_data)) != NULL) {
        this->data_ = static_cast<Real *>(data);
        this->dim_ = dim;
    } else {
        throw std::bad_alloc();
    }
}


template <typename Real>
void Vector<Real>::Resize(const MatrixIndexT dim,
                          MatrixResizeType resize_type) {
    // the next block uses recursion to handle what we have to do if
    // resize_type == kCopyData.
    if (resize_type == kCopyData) {
        if (this->data_ == NULL || dim == 0)
            resize_type = kSetZero;  // nothing to copy.
        else if (this->dim_ == dim) {
            return;
        }  // nothing to do.
        else {
            // set tmp to a vector of the desired size.
            Vector<Real> tmp(dim, kUndefined);
            if (dim > this->dim_) {
                memcpy(tmp.data_, this->data_, sizeof(Real) * this->dim_);
                memset(tmp.data_ + this->dim_,
                       0,
                       sizeof(Real) * (dim - this->dim_));
            } else {
                memcpy(tmp.data_, this->data_, sizeof(Real) * dim);
            }
            tmp.Swap(this);
            // and now let tmp go out of scope, deleting what was in *this.
            return;
        }
    }
    // At this point, resize_type == kSetZero or kUndefined.

    if (this->data_ != NULL) {
        if (this->dim_ == dim) {
            if (resize_type == kSetZero) this->SetZero();
            return;
        } else {
            Destroy();
        }
    }
    Init(dim);
    if (resize_type == kSetZero) this->SetZero();
}


/// Copy data from another vector
template <typename Real>
void VectorBase<Real>::CopyFromVec(const VectorBase<Real> &v) {
    KALDI_ASSERT(Dim() == v.Dim());
    if (data_ != v.data_) {
        std::memcpy(this->data_, v.data_, dim_ * sizeof(Real));
    }
}

/*
template<typename Real>
template<typename OtherReal>
void VectorBase<Real>::CopyFromPacked(const PackedMatrix<OtherReal>& M) {
  SubVector<OtherReal> v(M);
  this->CopyFromVec(v);
}
// instantiate the template.
template void VectorBase<float>::CopyFromPacked(const PackedMatrix<double>
&other);
template void VectorBase<float>::CopyFromPacked(const PackedMatrix<float>
&other);
template void VectorBase<double>::CopyFromPacked(const PackedMatrix<double>
&other);
template void VectorBase<double>::CopyFromPacked(const PackedMatrix<float>
&other);

/// Load data into the vector
template<typename Real>
void VectorBase<Real>::CopyFromPtr(const Real *data, MatrixIndexT sz) {
  KALDI_ASSERT(dim_ == sz);
  std::memcpy(this->data_, data, Dim() * sizeof(Real));
}*/

template <typename Real>
template <typename OtherReal>
void VectorBase<Real>::CopyFromVec(const VectorBase<OtherReal> &other) {
    KALDI_ASSERT(dim_ == other.Dim());
    Real *__restrict__ ptr = data_;
    const OtherReal *__restrict__ other_ptr = other.Data();
    for (MatrixIndexT i = 0; i < dim_; i++) ptr[i] = other_ptr[i];
}

template void VectorBase<float>::CopyFromVec(const VectorBase<double> &other);
template void VectorBase<double>::CopyFromVec(const VectorBase<float> &other);

// Remove element from the vector. The vector is not reallocated
template <typename Real>
void Vector<Real>::RemoveElement(MatrixIndexT i) {
    KALDI_ASSERT(i < this->dim_ && "Access out of vector");
    for (MatrixIndexT j = i + 1; j < this->dim_; j++)
        this->data_[j - 1] = this->data_[j];
    this->dim_--;
}


/// Deallocates memory and sets object to empty vector.
template <typename Real>
void Vector<Real>::Destroy() {
    /// we need to free the data block if it was defined
    if (this->data_ != NULL) KALDI_MEMALIGN_FREE(this->data_);
    this->data_ = NULL;
    this->dim_ = 0;
}

template <typename Real>
void VectorBase<Real>::SetZero() {
    std::memset(data_, 0, dim_ * sizeof(Real));
}

template <typename Real>
bool VectorBase<Real>::IsZero(Real cutoff) const {
    Real abs_max = 0.0;
    for (MatrixIndexT i = 0; i < Dim(); i++)
        abs_max = std::max(std::abs(data_[i]), abs_max);
    return (abs_max <= cutoff);
}

/*
template<typename Real>
void VectorBase<Real>::SetRandn() {
  kaldi::RandomState rstate;
  MatrixIndexT last = (Dim() % 2 == 1) ? Dim() - 1 : Dim();
  for (MatrixIndexT i = 0; i < last; i += 2) {
    kaldi::RandGauss2(data_ + i, data_ + i + 1, &rstate);
  }
  if (Dim() != last) data_[last] = static_cast<Real>(kaldi::RandGauss(&rstate));
}

template<typename Real>
void VectorBase<Real>::SetRandUniform() {
  kaldi::RandomState rstate;
  for (MatrixIndexT i = 0; i < Dim(); i++) {
    *(data_+i) = RandUniform(&rstate);
  }
}

template<typename Real>
MatrixIndexT VectorBase<Real>::RandCategorical() const {
  kaldi::RandomState rstate;
  Real sum = this->Sum();
  KALDI_ASSERT(this->Min() >= 0.0 && sum > 0.0);
  Real r = RandUniform(&rstate) * sum;
  Real *data = this->data_;
  MatrixIndexT dim = this->dim_;
  Real running_sum = 0.0;
  for (MatrixIndexT i = 0; i < dim; i++) {
    running_sum += data[i];
    if (r < running_sum) return i;
  }
  return dim_ - 1; // Should only happen if RandUniform()
                   // returns exactly 1, or due to roundoff.
}*/

template <typename Real>
void VectorBase<Real>::Set(Real f) {
    // Why not use memset here?
    // The basic unit of memset is a byte.
    // If f != 0 and sizeof(Real) > 1, then we cannot use memset.
    if (f == 0) {
        this->SetZero();  // calls std::memset
    } else {
        for (MatrixIndexT i = 0; i < dim_; i++) {
            data_[i] = f;
        }
    }
}

template <typename Real>
void VectorBase<Real>::CopyRowsFromMat(const MatrixBase<Real> &mat) {
    KALDI_ASSERT(dim_ == mat.NumCols() * mat.NumRows());

    Real *inc_data = data_;
    const MatrixIndexT cols = mat.NumCols(), rows = mat.NumRows();

    if (mat.Stride() == mat.NumCols()) {
        memcpy(inc_data, mat.Data(), cols * rows * sizeof(Real));
    } else {
        for (MatrixIndexT i = 0; i < rows; i++) {
            // copy the data to the proper position
            memcpy(inc_data, mat.RowData(i), cols * sizeof(Real));
            // set new copy position
            inc_data += cols;
        }
    }
}

template <typename Real>
template <typename OtherReal>
void VectorBase<Real>::CopyRowsFromMat(const MatrixBase<OtherReal> &mat) {
    KALDI_ASSERT(dim_ == mat.NumCols() * mat.NumRows());
    Real *vec_data = data_;
    const MatrixIndexT cols = mat.NumCols(), rows = mat.NumRows();

    for (MatrixIndexT i = 0; i < rows; i++) {
        const OtherReal *mat_row = mat.RowData(i);
        for (MatrixIndexT j = 0; j < cols; j++) {
            vec_data[j] = static_cast<Real>(mat_row[j]);
        }
        vec_data += cols;
    }
}

template void VectorBase<float>::CopyRowsFromMat(const MatrixBase<double> &mat);
template void VectorBase<double>::CopyRowsFromMat(const MatrixBase<float> &mat);


template <typename Real>
void VectorBase<Real>::CopyColsFromMat(const MatrixBase<Real> &mat) {
    KALDI_ASSERT(dim_ == mat.NumCols() * mat.NumRows());

    Real *inc_data = data_;
    const MatrixIndexT cols = mat.NumCols(), rows = mat.NumRows(),
                       stride = mat.Stride();
    const Real *mat_inc_data = mat.Data();

    for (MatrixIndexT i = 0; i < cols; i++) {
        for (MatrixIndexT j = 0; j < rows; j++) {
            inc_data[j] = mat_inc_data[j * stride];
        }
        mat_inc_data++;
        inc_data += rows;
    }
}

template <typename Real>
void VectorBase<Real>::CopyRowFromMat(const MatrixBase<Real> &mat,
                                      MatrixIndexT row) {
    KALDI_ASSERT(row < mat.NumRows());
    KALDI_ASSERT(dim_ == mat.NumCols());
    const Real *mat_row = mat.RowData(row);
    memcpy(data_, mat_row, sizeof(Real) * dim_);
}

template <typename Real>
template <typename OtherReal>
void VectorBase<Real>::CopyRowFromMat(const MatrixBase<OtherReal> &mat,
                                      MatrixIndexT row) {
    KALDI_ASSERT(row < mat.NumRows());
    KALDI_ASSERT(dim_ == mat.NumCols());
    const OtherReal *mat_row = mat.RowData(row);
    for (MatrixIndexT i = 0; i < dim_; i++)
        data_[i] = static_cast<Real>(mat_row[i]);
}

template void VectorBase<float>::CopyRowFromMat(const MatrixBase<double> &mat,
                                                MatrixIndexT row);
template void VectorBase<double>::CopyRowFromMat(const MatrixBase<float> &mat,
                                                 MatrixIndexT row);

/*
template<typename Real>
template<typename OtherReal>
void VectorBase<Real>::CopyRowFromSp(const SpMatrix<OtherReal> &sp, MatrixIndexT
row) {
  KALDI_ASSERT(row < sp.NumRows());
  KALDI_ASSERT(dim_ == sp.NumCols());

  const OtherReal *sp_data = sp.Data();

  sp_data += (row*(row+1)) / 2; // takes us to beginning of this row.
  MatrixIndexT i;
  for (i = 0; i < row; i++) // copy consecutive elements.
    data_[i] = static_cast<Real>(*(sp_data++));
  for(; i < dim_; ++i, sp_data += i)
    data_[i] = static_cast<Real>(*sp_data);
}

template
void VectorBase<float>::CopyRowFromSp(const SpMatrix<double> &mat, MatrixIndexT
row);
template
void VectorBase<double>::CopyRowFromSp(const SpMatrix<float> &mat, MatrixIndexT
row);
template
void VectorBase<float>::CopyRowFromSp(const SpMatrix<float> &mat, MatrixIndexT
row);
template
void VectorBase<double>::CopyRowFromSp(const SpMatrix<double> &mat, MatrixIndexT
row);

// takes absolute value of the elements to a power.
// Throws exception if could not (but only for power != 1 and power != 2).
template<typename Real>
void VectorBase<Real>::ApplyPowAbs(Real power, bool include_sign) {
  if (power == 1.0)
    for (MatrixIndexT i = 0; i < dim_; i++)
      data_[i] = (include_sign && data_[i] < 0 ? -1 : 1) * std::abs(data_[i]);
  if (power == 2.0) {
    for (MatrixIndexT i = 0; i < dim_; i++)
      data_[i] = (include_sign && data_[i] < 0 ? -1 : 1) * data_[i] * data_[i];
  } else if (power == 0.5) {
    for (MatrixIndexT i = 0; i < dim_; i++) {
      data_[i] = (include_sign && data_[i] < 0 ? -1 : 1) *
std::sqrt(std::abs(data_[i]));
    }
  } else if (power < 0.0) {
    for (MatrixIndexT i = 0; i < dim_; i++) {
      data_[i] = (data_[i] == 0.0 ? 0.0 : pow(std::abs(data_[i]), power));
      data_[i] *= (include_sign && data_[i] < 0 ? -1 : 1);
      if (data_[i] == HUGE_VAL) {  // HUGE_VAL is what errno returns on error.
        KALDI_ERR << "Could not raise element "  << i << "to power "
                  << power << ": returned value = " << data_[i];
      }
    }
  } else {
    for (MatrixIndexT i = 0; i < dim_; i++) {
      data_[i] = (include_sign && data_[i] < 0 ? -1 : 1) *
pow(std::abs(data_[i]), power);
      if (data_[i] == HUGE_VAL) {  // HUGE_VAL is what errno returns on error.
        KALDI_ERR << "Could not raise element "  << i << "to power "
                  << power << ": returned value = " << data_[i];
      }
    }
  }
}

// Computes the p-th norm. Throws exception if could not.
template<typename Real>
Real VectorBase<Real>::Norm(Real p) const {
  KALDI_ASSERT(p >= 0.0);
  Real sum = 0.0;
  if (p == 0.0) {
    for (MatrixIndexT i = 0; i < dim_; i++)
      if (data_[i] != 0.0) sum += 1.0;
    return sum;
  } else if (p == 1.0) {
    for (MatrixIndexT i = 0; i < dim_; i++)
      sum += std::abs(data_[i]);
    return sum;
  } else if (p == 2.0) {
    for (MatrixIndexT i = 0; i < dim_; i++)
      sum += data_[i] * data_[i];
    return std::sqrt(sum);
  } else if (p == std::numeric_limits<Real>::infinity()){
    for (MatrixIndexT i = 0; i < dim_; i++)
      sum = std::max(sum, std::abs(data_[i]));
    return sum;
  } else {
    Real tmp;
    bool ok = true;
    for (MatrixIndexT i = 0; i < dim_; i++) {
      tmp = pow(std::abs(data_[i]), p);
      if (tmp == HUGE_VAL) // HUGE_VAL is what pow returns on error.
        ok = false;
      sum += tmp;
    }
    tmp = pow(sum, static_cast<Real>(1.0/p));
    KALDI_ASSERT(tmp != HUGE_VAL); // should not happen here.
    if (ok) {
      return tmp;
    } else {
      Real maximum = this->Max(), minimum = this->Min(),
          max_abs = std::max(maximum, -minimum);
      KALDI_ASSERT(max_abs > 0); // Or should not have reached here.
      Vector<Real> tmp(*this);
      tmp.Scale(1.0 / max_abs);
      return tmp.Norm(p) * max_abs;
    }
  }
}

template<typename Real>
bool VectorBase<Real>::ApproxEqual(const VectorBase<Real> &other, float tol)
const {
  if (dim_ != other.dim_) KALDI_ERR << "ApproxEqual: size mismatch "
                                    << dim_ << " vs. " << other.dim_;
  KALDI_ASSERT(tol >= 0.0);
  if (tol != 0.0) {
    Vector<Real> tmp(*this);
    tmp.AddVec(-1.0, other);
    return (tmp.Norm(2.0) <= static_cast<Real>(tol) * this->Norm(2.0));
  } else { // Test for exact equality.
    const Real *data = data_;
    const Real *other_data = other.data_;
    for (MatrixIndexT dim = dim_, i = 0; i < dim; i++)
      if (data[i] != other_data[i]) return false;
    return true;
  }
}

template<typename Real>
Real VectorBase<Real>::Max() const {
  Real ans = - std::numeric_limits<Real>::infinity();
  const Real *data = data_;
  MatrixIndexT i, dim = dim_;
  for (i = 0; i + 4 <= dim; i += 4) {
    Real a1 = data[i], a2 = data[i+1], a3 = data[i+2], a4 = data[i+3];
    if (a1 > ans || a2 > ans || a3 > ans || a4 > ans) {
      Real b1 = (a1 > a2 ? a1 : a2), b2 = (a3 > a4 ? a3 : a4);
      if (b1 > ans) ans = b1;
      if (b2 > ans) ans = b2;
    }
  }
  for (; i < dim; i++)
    if (data[i] > ans) ans = data[i];
  return ans;
}

template<typename Real>
Real VectorBase<Real>::Max(MatrixIndexT *index_out) const {
  if (dim_ == 0) KALDI_ERR << "Empty vector";
  Real ans = - std::numeric_limits<Real>::infinity();
  MatrixIndexT index = 0;
  const Real *data = data_;
  MatrixIndexT i, dim = dim_;
  for (i = 0; i + 4 <= dim; i += 4) {
    Real a1 = data[i], a2 = data[i+1], a3 = data[i+2], a4 = data[i+3];
    if (a1 > ans || a2 > ans || a3 > ans || a4 > ans) {
      if (a1 > ans) { ans = a1; index = i; }
      if (a2 > ans) { ans = a2; index = i + 1; }
      if (a3 > ans) { ans = a3; index = i + 2; }
      if (a4 > ans) { ans = a4; index = i + 3; }
    }
  }
  for (; i < dim; i++)
    if (data[i] > ans) { ans = data[i]; index = i; }
  *index_out = index;
  return ans;
}

template<typename Real>
Real VectorBase<Real>::Min() const {
  Real ans = std::numeric_limits<Real>::infinity();
  const Real *data = data_;
  MatrixIndexT i, dim = dim_;
  for (i = 0; i + 4 <= dim; i += 4) {
    Real a1 = data[i], a2 = data[i+1], a3 = data[i+2], a4 = data[i+3];
    if (a1 < ans || a2 < ans || a3 < ans || a4 < ans) {
      Real b1 = (a1 < a2 ? a1 : a2), b2 = (a3 < a4 ? a3 : a4);
      if (b1 < ans) ans = b1;
      if (b2 < ans) ans = b2;
    }
  }
  for (; i < dim; i++)
    if (data[i] < ans) ans = data[i];
  return ans;
}

template<typename Real>
Real VectorBase<Real>::Min(MatrixIndexT *index_out) const {
  if (dim_ == 0) KALDI_ERR << "Empty vector";
  Real ans = std::numeric_limits<Real>::infinity();
  MatrixIndexT index = 0;
  const Real *data = data_;
  MatrixIndexT i, dim = dim_;
  for (i = 0; i + 4 <= dim; i += 4) {
    Real a1 = data[i], a2 = data[i+1], a3 = data[i+2], a4 = data[i+3];
    if (a1 < ans || a2 < ans || a3 < ans || a4 < ans) {
      if (a1 < ans) { ans = a1; index = i; }
      if (a2 < ans) { ans = a2; index = i + 1; }
      if (a3 < ans) { ans = a3; index = i + 2; }
      if (a4 < ans) { ans = a4; index = i + 3; }
    }
  }
  for (; i < dim; i++)
    if (data[i] < ans) { ans = data[i]; index = i; }
  *index_out = index;
  return ans;
}*/


template <typename Real>
template <typename OtherReal>
void VectorBase<Real>::CopyColFromMat(const MatrixBase<OtherReal> &mat,
                                      MatrixIndexT col) {
    KALDI_ASSERT(col < mat.NumCols());
    KALDI_ASSERT(dim_ == mat.NumRows());
    for (MatrixIndexT i = 0; i < dim_; i++) data_[i] = mat(i, col);
    // can't do this very efficiently so don't really bother. could improve this
    // though.
}
// instantiate the template above.
template void VectorBase<float>::CopyColFromMat(const MatrixBase<float> &mat,
                                                MatrixIndexT col);
template void VectorBase<float>::CopyColFromMat(const MatrixBase<double> &mat,
                                                MatrixIndexT col);
template void VectorBase<double>::CopyColFromMat(const MatrixBase<float> &mat,
                                                 MatrixIndexT col);
template void VectorBase<double>::CopyColFromMat(const MatrixBase<double> &mat,
                                                 MatrixIndexT col);

// template<typename Real>
// void VectorBase<Real>::CopyDiagFromMat(const MatrixBase<Real> &M) {
// KALDI_ASSERT(dim_ == std::min(M.NumRows(), M.NumCols()));
// cblas_Xcopy(dim_, M.Data(), M.Stride() + 1, data_, 1);
//}

// template<typename Real>
// void VectorBase<Real>::CopyDiagFromPacked(const PackedMatrix<Real> &M) {
// KALDI_ASSERT(dim_ == M.NumCols());
// for (MatrixIndexT i = 0; i < dim_; i++)
// data_[i] = M(i, i);
//// could make this more efficient.
//}

// template<typename Real>
// Real VectorBase<Real>::Sum() const {
//// Do a dot-product with a size-1 array with a stride of 0 to
//// implement sum. This allows us to access SIMD operations in a
//// cross-platform way via your BLAS library.
// Real one(1);
// return cblas_Xdot(dim_, data_, 1, &one, 0);
//}

// template<typename Real>
// Real VectorBase<Real>::SumLog() const {
// double sum_log = 0.0;
// double prod = 1.0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// prod *= data_[i];
//// Possible future work (arnab): change these magic values to pre-defined
//// constants
// if (prod < 1.0e-10 || prod > 1.0e+10) {
// sum_log += Log(prod);
// prod = 1.0;
//}
//}
// if (prod != 1.0) sum_log += Log(prod);
// return sum_log;
//}

// template<typename Real>
// void VectorBase<Real>::AddRowSumMat(Real alpha, const MatrixBase<Real> &M,
// Real beta) {
// KALDI_ASSERT(dim_ == M.NumCols());
// MatrixIndexT num_rows = M.NumRows(), stride = M.Stride(), dim = dim_;
// Real *data = data_;

//// implement the function according to a dimension cutoff for computation
/// efficiency
// if (num_rows <= 64) {
// cblas_Xscal(dim, beta, data, 1);
// const Real *m_data = M.Data();
// for (MatrixIndexT i = 0; i < num_rows; i++, m_data += stride)
// cblas_Xaxpy(dim, alpha, m_data, 1, data, 1);

//} else {
// Vector<Real> ones(M.NumRows());
// ones.Set(1.0);
// this->AddMatVec(alpha, M, kTrans, ones, beta);
//}
//}

// template<typename Real>
// void VectorBase<Real>::AddColSumMat(Real alpha, const MatrixBase<Real> &M,
// Real beta) {
// KALDI_ASSERT(dim_ == M.NumRows());
// MatrixIndexT num_cols = M.NumCols();

//// implement the function according to a dimension cutoff for computation
/// efficiency
// if (num_cols <= 64) {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// double sum = 0.0;
// const Real *src = M.RowData(i);
// for (MatrixIndexT j = 0; j < num_cols; j++)
// sum += src[j];
// data_[i] = alpha * sum + beta * data_[i];
//}
//} else {
// Vector<Real> ones(M.NumCols());
// ones.Set(1.0);
// this->AddMatVec(alpha, M, kNoTrans, ones, beta);
//}
//}

// template<typename Real>
// Real VectorBase<Real>::LogSumExp(Real prune) const {
// Real sum;
// if (sizeof(sum) == 8) sum = kLogZeroDouble;
// else sum = kLogZeroFloat;
// Real max_elem = Max(), cutoff;
// if (sizeof(Real) == 4) cutoff = max_elem + kMinLogDiffFloat;
// else cutoff = max_elem + kMinLogDiffDouble;
// if (prune > 0.0 && max_elem - prune > cutoff) // explicit pruning...
// cutoff = max_elem - prune;

// double sum_relto_max_elem = 0.0;

// for (MatrixIndexT i = 0; i < dim_; i++) {
// BaseFloat f = data_[i];
// if (f >= cutoff)
// sum_relto_max_elem += Exp(f - max_elem);
//}
// return max_elem + Log(sum_relto_max_elem);
//}

// template<typename Real>
// void VectorBase<Real>::InvertElements() {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = static_cast<Real>(1 / data_[i]);
//}
//}

// template<typename Real>
// void VectorBase<Real>::ApplyLog() {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// if (data_[i] < 0.0)
// KALDI_ERR << "Trying to take log of a negative number.";
// data_[i] = Log(data_[i]);
//}
//}

// template<typename Real>
// void VectorBase<Real>::ApplyLogAndCopy(const VectorBase<Real> &v) {
// KALDI_ASSERT(dim_ == v.Dim());
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = Log(v(i));
//}
//}

// template<typename Real>
// void VectorBase<Real>::ApplyExp() {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = Exp(data_[i]);
//}
//}

// template<typename Real>
// void VectorBase<Real>::ApplyAbs() {
// for (MatrixIndexT i = 0; i < dim_; i++) { data_[i] = std::abs(data_[i]); }
//}

// template<typename Real>
// void VectorBase<Real>::Floor(const VectorBase<Real> &v, Real floor_val,
// MatrixIndexT *floored_count) {
// KALDI_ASSERT(dim_ == v.dim_);
// if (floored_count == nullptr) {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = std::max(v.data_[i], floor_val);
//}
//} else {
// MatrixIndexT num_floored = 0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// if (v.data_[i] < floor_val) {
// data_[i] = floor_val;
// num_floored++;
//} else {
// data_[i] = v.data_[i];
//}
//}
//*floored_count = num_floored;
//}
//}

// template<typename Real>
// void VectorBase<Real>::Ceiling(const VectorBase<Real> &v, Real ceil_val,
// MatrixIndexT *ceiled_count) {
// KALDI_ASSERT(dim_ == v.dim_);
// if (ceiled_count == nullptr) {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = std::min(v.data_[i], ceil_val);
//}
//} else {
// MatrixIndexT num_changed = 0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// if (v.data_[i] > ceil_val) {
// data_[i] = ceil_val;
// num_changed++;
//} else {
// data_[i] = v.data_[i];
//}
//}
//*ceiled_count = num_changed;
//}
//}

// template<typename Real>
// MatrixIndexT VectorBase<Real>::ApplyFloor(const VectorBase<Real> &floor_vec)
// {
// KALDI_ASSERT(floor_vec.Dim() == dim_);
// MatrixIndexT num_floored = 0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// if (data_[i] < floor_vec(i)) {
// data_[i] = floor_vec(i);
// num_floored++;
//}
//}
// return num_floored;
//}

// template<typename Real>
// Real VectorBase<Real>::ApplySoftMax() {
// Real max = this->Max(), sum = 0.0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// sum += (data_[i] = Exp(data_[i] - max));
//}
// this->Scale(1.0 / sum);
// return max + Log(sum);
//}

// template<typename Real>
// Real VectorBase<Real>::ApplyLogSoftMax() {
// Real max = this->Max(), sum = 0.0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// sum += Exp((data_[i] -= max));
//}
// sum = Log(sum);
// this->Add(-1.0 * sum);
// return max + sum;
//}

//#ifdef HAVE_MKL
// template<>
// void VectorBase<float>::Tanh(const VectorBase<float> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// vsTanh(dim_, src.data_, data_);
//}
// template<>
// void VectorBase<double>::Tanh(const VectorBase<double> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// vdTanh(dim_, src.data_, data_);
//}
//#else
// template<typename Real>
// void VectorBase<Real>::Tanh(const VectorBase<Real> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// for (MatrixIndexT i = 0; i < dim_; i++) {
// Real x = src.data_[i];
// if (x > 0.0) {
// Real inv_expx = Exp(-x);
// x = -1.0 + 2.0 / (1.0 + inv_expx * inv_expx);
//} else {
// Real expx = Exp(x);
// x = 1.0 - 2.0 / (1.0 + expx * expx);
//}
// data_[i] = x;
//}
//}
//#endif

//#ifdef HAVE_MKL
//// Implementing sigmoid based on tanh.
// template<>
// void VectorBase<float>::Sigmoid(const VectorBase<float> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// this->CopyFromVec(src);
// this->Scale(0.5);
// vsTanh(dim_, data_, data_);
// this->Add(1.0);
// this->Scale(0.5);
//}
// template<>
// void VectorBase<double>::Sigmoid(const VectorBase<double> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// this->CopyFromVec(src);
// this->Scale(0.5);
// vdTanh(dim_, data_, data_);
// this->Add(1.0);
// this->Scale(0.5);
//}
//#else
// template<typename Real>
// void VectorBase<Real>::Sigmoid(const VectorBase<Real> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// for (MatrixIndexT i = 0; i < dim_; i++) {
// Real x = src.data_[i];
//// We aim to avoid floating-point overflow here.
// if (x > 0.0) {
// x = 1.0 / (1.0 + Exp(-x));
//} else {
// Real ex = Exp(x);
// x = ex / (ex + 1.0);
//}
// data_[i] = x;
//}
//}
//#endif


// template<typename Real>
// void VectorBase<Real>::Add(Real c) {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] += c;
//}
//}

// template<typename Real>
// void VectorBase<Real>::Scale(Real alpha) {
// cblas_Xscal(dim_, alpha, data_, 1);
//}

// template<typename Real>
// void VectorBase<Real>::MulElements(const VectorBase<Real> &v) {
// KALDI_ASSERT(dim_ == v.dim_);
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] *= v.data_[i];
//}
//}

// template<typename Real>  // Set each element to y = (x == orig ? changed :
// x).
// void VectorBase<Real>::ReplaceValue(Real orig, Real changed) {
// Real *data = data_;
// for (MatrixIndexT i = 0; i < dim_; i++)
// if (data[i] == orig) data[i] = changed;
//}


// template<typename Real>
// template<typename OtherReal>
// void VectorBase<Real>::MulElements(const VectorBase<OtherReal> &v) {
// KALDI_ASSERT(dim_ == v.Dim());
// const OtherReal *other_ptr = v.Data();
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] *= other_ptr[i];
//}
//}
//// instantiate template.
// template
// void VectorBase<float>::MulElements(const VectorBase<double> &v);
// template
// void VectorBase<double>::MulElements(const VectorBase<float> &v);


// template<typename Real>
// void VectorBase<Real>::AddVecVec(Real alpha, const VectorBase<Real> &v,
// const VectorBase<Real> &r, Real beta) {
// KALDI_ASSERT(v.data_ != this->data_ && r.data_ != this->data_);
//// We pretend that v is a band-diagonal matrix.
// KALDI_ASSERT(dim_ == v.dim_ && dim_ == r.dim_);
// cblas_Xgbmv(kNoTrans, dim_, dim_, 0, 0, alpha, v.data_, 1,
// r.data_, 1, beta, this->data_, 1);
//}


// template<typename Real>
// void VectorBase<Real>::DivElements(const VectorBase<Real> &v) {
// KALDI_ASSERT(dim_ == v.dim_);
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] /= v.data_[i];
//}
//}

// template<typename Real>
// template<typename OtherReal>
// void VectorBase<Real>::DivElements(const VectorBase<OtherReal> &v) {
// KALDI_ASSERT(dim_ == v.Dim());
// const OtherReal *other_ptr = v.Data();
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] /= other_ptr[i];
//}
//}
//// instantiate template.
// template
// void VectorBase<float>::DivElements(const VectorBase<double> &v);
// template
// void VectorBase<double>::DivElements(const VectorBase<float> &v);

// template<typename Real>
// void VectorBase<Real>::AddVecDivVec(Real alpha, const VectorBase<Real> &v,
// const VectorBase<Real> &rr, Real beta) {
// KALDI_ASSERT((dim_ == v.dim_ && dim_ == rr.dim_));
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = alpha * v.data_[i]/rr.data_[i] + beta * data_[i] ;
//}
//}

// template<typename Real>
// template<typename OtherReal>
// void VectorBase<Real>::AddVec(const Real alpha, const VectorBase<OtherReal>
// &v) {
// KALDI_ASSERT(dim_ == v.dim_);
//// remove __restrict__ if it causes compilation problems.
// Real *__restrict__ data = data_;
// OtherReal *__restrict__ other_data = v.data_;
// MatrixIndexT dim = dim_;
// if (alpha != 1.0)
// for (MatrixIndexT i = 0; i < dim; i++)
// data[i] += alpha * other_data[i];
// else
// for (MatrixIndexT i = 0; i < dim; i++)
// data[i] += other_data[i];
//}

// template
// void VectorBase<float>::AddVec(const float alpha, const VectorBase<double>
// &v);
// template
// void VectorBase<double>::AddVec(const double alpha, const VectorBase<float>
// &v);

// template<typename Real>
// template<typename OtherReal>
// void VectorBase<Real>::AddVec2(const Real alpha, const VectorBase<OtherReal>
// &v) {
// KALDI_ASSERT(dim_ == v.dim_);
//// remove __restrict__ if it causes compilation problems.
// Real *__restrict__ data = data_;
// OtherReal *__restrict__ other_data = v.data_;
// MatrixIndexT dim = dim_;
// if (alpha != 1.0)
// for (MatrixIndexT i = 0; i < dim; i++)
// data[i] += alpha * other_data[i] * other_data[i];
// else
// for (MatrixIndexT i = 0; i < dim; i++)
// data[i] += other_data[i] * other_data[i];
//}

// template
// void VectorBase<float>::AddVec2(const float alpha, const VectorBase<double>
// &v);
// template
// void VectorBase<double>::AddVec2(const double alpha, const VectorBase<float>
// &v);


template <typename Real>
void VectorBase<Real>::Read(std::istream &is, bool binary) {
    //  In order to avoid rewriting this, we just declare a Vector and
    // use it to read the data, then copy.
    Vector<Real> tmp;
    tmp.Read(is, binary);
    if (tmp.Dim() != Dim())
        KALDI_ERR << "VectorBase<Real>::Read, size mismatch " << Dim()
                  << " vs. " << tmp.Dim();
    CopyFromVec(tmp);
}


template <typename Real>
void Vector<Real>::Read(std::istream &is, bool binary) {
    std::ostringstream specific_error;
    MatrixIndexT pos_at_start = is.tellg();

    if (binary) {
        int peekval = Peek(is, binary);
        const char *my_token = (sizeof(Real) == 4 ? "FV" : "DV");
        char other_token_start = (sizeof(Real) == 4 ? 'D' : 'F');
        if (peekval == other_token_start) {  // need to instantiate the other
                                             // type to read it.
            typedef typename OtherReal<Real>::Real OtherType;  // if Real ==
                                                               // float,
                                                               // OtherType ==
                                                               // double, and
                                                               // vice versa.
            Vector<OtherType> other(this->Dim());
            other.Read(is, binary);  // add is false at this point.
            if (this->Dim() != other.Dim()) this->Resize(other.Dim());
            this->CopyFromVec(other);
            return;
        }
        std::string token;
        ReadToken(is, binary, &token);
        if (token != my_token) {
            if (token.length() > 20) token = token.substr(0, 17) + "...";
            specific_error << ": Expected token " << my_token << ", got "
                           << token;
            goto bad;
        }
        int32 size;
        ReadBasicType(is, binary, &size);  // throws on error.
        if ((MatrixIndexT)size != this->Dim()) this->Resize(size);
        if (size > 0)
            is.read(reinterpret_cast<char *>(this->data_), sizeof(Real) * size);
        if (is.fail()) {
            specific_error
                << "Error reading vector data (binary mode); truncated "
                   "stream? (size = "
                << size << ")";
            goto bad;
        }
        return;
    } else {  // Text mode reading; format is " [ 1.1 2.0 3.4 ]\n"
        std::string s;
        is >> s;
        // if ((s.compare("DV") == 0) || (s.compare("FV") == 0)) {  // Back
        // compatibility.
        //  is >> s;  // get dimension
        //  is >> s;  // get "["
        // }
        if (is.fail()) {
            specific_error << "EOF while trying to read vector.";
            goto bad;
        }
        if (s.compare("[]") == 0) {
            Resize(0);
            return;
        }  // tolerate this variant.
        if (s.compare("[")) {
            if (s.length() > 20) s = s.substr(0, 17) + "...";
            specific_error << "Expected \"[\" but got " << s;
            goto bad;
        }
        std::vector<Real> data;
        while (1) {
            int i = is.peek();
            if (i == '-' || (i >= '0' && i <= '9')) {  // common cases first.
                Real r;
                is >> r;
                if (is.fail()) {
                    specific_error << "Failed to read number.";
                    goto bad;
                }
                if (!std::isspace(is.peek()) && is.peek() != ']') {
                    specific_error << "Expected whitespace after number.";
                    goto bad;
                }
                data.push_back(r);
                // But don't eat whitespace... we want to check that it's not
                // newlines
                // which would be valid only for a matrix.
            } else if (i == ' ' || i == '\t') {
                is.get();
            } else if (i == ']') {
                is.get();  // eat the ']'
                this->Resize(data.size());
                for (size_t j = 0; j < data.size(); j++)
                    this->data_[j] = data[j];
                i = is.peek();
                if (static_cast<char>(i) == '\r') {
                    is.get();
                    is.get();  // get \r\n (must eat what we wrote)
                } else if (static_cast<char>(i) == '\n') {
                    is.get();
                }  // get \n (must eat what we wrote)
                if (is.fail()) {
                    KALDI_WARN << "After end of vector data, read error.";
                    // we got the data we needed, so just warn for this error.
                }
                return;  // success.
            } else if (i == -1) {
                specific_error << "EOF while reading vector data.";
                goto bad;
            } else if (i == '\n' || i == '\r') {
                specific_error << "Newline found while reading vector (maybe "
                                  "it's a matrix?)";
                goto bad;
            } else {
                is >> s;  // read string.
                if (!KALDI_STRCASECMP(s.c_str(), "inf") ||
                    !KALDI_STRCASECMP(s.c_str(), "infinity")) {
                    data.push_back(std::numeric_limits<Real>::infinity());
                    KALDI_WARN << "Reading infinite value into vector.";
                } else if (!KALDI_STRCASECMP(s.c_str(), "nan")) {
                    data.push_back(std::numeric_limits<Real>::quiet_NaN());
                    KALDI_WARN << "Reading NaN value into vector.";
                } else {
                    if (s.length() > 20) s = s.substr(0, 17) + "...";
                    specific_error << "Expecting numeric vector data, got "
                                   << s;
                    goto bad;
                }
            }
        }
    }
// we never reach this line (the while loop returns directly).
bad:
    KALDI_ERR << "Failed to read vector from stream.  " << specific_error.str()
              << " File position at start is " << pos_at_start << ", currently "
              << is.tellg();
}


template <typename Real>
void VectorBase<Real>::Write(std::ostream &os, bool binary) const {
    if (!os.good()) {
        KALDI_ERR << "Failed to write vector to stream: stream not good";
    }
    if (binary) {
        std::string my_token = (sizeof(Real) == 4 ? "FV" : "DV");
        WriteToken(os, binary, my_token);

        int32 size = Dim();  // make the size 32-bit on disk.
        KALDI_ASSERT(Dim() == (MatrixIndexT)size);
        WriteBasicType(os, binary, size);
        os.write(reinterpret_cast<const char *>(Data()), sizeof(Real) * size);
    } else {
        os << " [ ";
        for (MatrixIndexT i = 0; i < Dim(); i++) os << (*this)(i) << " ";
        os << "]\n";
    }
    if (!os.good()) KALDI_ERR << "Failed to write vector to stream";
}


// template<typename Real>
// void VectorBase<Real>::AddVec2(const Real alpha, const VectorBase<Real> &v) {
// KALDI_ASSERT(dim_ == v.dim_);
// for (MatrixIndexT i = 0; i < dim_; i++)
// data_[i] += alpha * v.data_[i] * v.data_[i];
//}

//// this <-- beta*this + alpha*M*v.
// template<typename Real>
// void VectorBase<Real>::AddTpVec(const Real alpha, const TpMatrix<Real> &M,
// const MatrixTransposeType trans,
// const VectorBase<Real> &v,
// const Real beta) {
// KALDI_ASSERT(dim_ == v.dim_ && dim_ == M.NumRows());
// if (beta == 0.0) {
// if (&v != this) CopyFromVec(v);
// MulTp(M, trans);
// if (alpha != 1.0) Scale(alpha);
//} else {
// Vector<Real> tmp(v);
// tmp.MulTp(M, trans);
// if (beta != 1.0) Scale(beta);  // *this <-- beta * *this
// AddVec(alpha, tmp);          // *this += alpha * M * v
//}
//}

// template<typename Real>
// Real VecMatVec(const VectorBase<Real> &v1, const MatrixBase<Real> &M,
// const VectorBase<Real> &v2) {
// KALDI_ASSERT(v1.Dim() == M.NumRows() && v2.Dim() == M.NumCols());
// Vector<Real> vtmp(M.NumRows());
// vtmp.AddMatVec(1.0, M, kNoTrans, v2, 0.0);
// return VecVec(v1, vtmp);
//}

// template
// float VecMatVec(const VectorBase<float> &v1, const MatrixBase<float> &M,
// const VectorBase<float> &v2);
// template
// double VecMatVec(const VectorBase<double> &v1, const MatrixBase<double> &M,
// const VectorBase<double> &v2);

template <typename Real>
void Vector<Real>::Swap(Vector<Real> *other) {
    std::swap(this->data_, other->data_);
    std::swap(this->dim_, other->dim_);
}


// template<typename Real>
// void VectorBase<Real>::AddDiagMat2(
// Real alpha, const MatrixBase<Real> &M,
// MatrixTransposeType trans, Real beta) {
// if (trans == kNoTrans) {
// KALDI_ASSERT(this->dim_ == M.NumRows());
// MatrixIndexT rows = this->dim_, cols = M.NumCols(),
// mat_stride = M.Stride();
// Real *data = this->data_;
// const Real *mat_data = M.Data();
// for (MatrixIndexT i = 0; i < rows; i++, mat_data += mat_stride, data++)
//*data = beta * *data + alpha * cblas_Xdot(cols,mat_data,1,mat_data,1);
//} else {
// KALDI_ASSERT(this->dim_ == M.NumCols());
// MatrixIndexT rows = M.NumRows(), cols = this->dim_,
// mat_stride = M.Stride();
// Real *data = this->data_;
// const Real *mat_data = M.Data();
// for (MatrixIndexT i = 0; i < cols; i++, mat_data++, data++)
//*data = beta * *data + alpha * cblas_Xdot(rows, mat_data, mat_stride,
// mat_data, mat_stride);
//}
//}

// template<typename Real>
// void VectorBase<Real>::AddDiagMatMat(
// Real alpha,
// const MatrixBase<Real> &M, MatrixTransposeType transM,
// const MatrixBase<Real> &N, MatrixTransposeType transN,
// Real beta) {
// MatrixIndexT dim = this->dim_,
// M_col_dim = (transM == kTrans ? M.NumRows() : M.NumCols()),
// N_row_dim = (transN == kTrans ? N.NumCols() : N.NumRows());
// KALDI_ASSERT(M_col_dim == N_row_dim); // this is the dimension we sum over
// MatrixIndexT M_row_stride = M.Stride(), M_col_stride = 1;
// if (transM == kTrans) std::swap(M_row_stride, M_col_stride);
// MatrixIndexT N_row_stride = N.Stride(), N_col_stride = 1;
// if (transN == kTrans) std::swap(N_row_stride, N_col_stride);

// Real *data = this->data_;
// const Real *Mdata = M.Data(), *Ndata = N.Data();
// for (MatrixIndexT i = 0; i < dim; i++, Mdata += M_row_stride, Ndata +=
// N_col_stride, data++) {
//*data = beta * *data + alpha * cblas_Xdot(M_col_dim, Mdata, M_col_stride,
// Ndata, N_row_stride);
//}
//}


template class Vector<float>;
template class Vector<double>;
template class VectorBase<float>;
template class VectorBase<double>;

}  // namespace kaldi
